
/**
 * 获取数组元素出现的次数
 * @param {Array<number & string>} arr
 * @return { object }
 */
export const getRepeatCount = function (arr: Array<number & string>) {
  const res = {} as any;
  arr.forEach(item => {
    if (res[item] === undefined) {
      res[item] = 1;
    } else {
      res[item]++;
    }
  });
  return res;
}

type SortOrder = 'asc' | 'desc';

interface SortOption<T> {
  len?: number;
  key: keyof T;
  order: SortOrder;
}

export class InsertSortedArray<T extends Record<string, any>> {
  private array: T[];
  private sortOption: SortOption<T>;
  private size: 0;

  constructor(sortOption: SortOption<T>) {
    this.array = [];
    this.sortOption = sortOption;
  }

  public add(item: T) {
    const index = this.binarySearch(item);
    this.array.splice(index, 0, item);

  }

  public getArray() {
    return this.array;
  }

  private binarySearch(item: T) {
    let left = 0;
    let right = this.array.length - 1;
    const { key, order } = this.sortOption;

    while (left <= right) {
      const mid = Math.floor((left + right) / 2);
      const midValue = this.array[mid][key];
      const value = item[key]
      if ((order === 'asc' && midValue < value) || (order === 'desc' && midValue > value)) {
        left = mid + 1;
      } else if ((order === 'asc' && midValue > value) || (order === 'desc' && midValue < value)) {
        right = mid - 1;
      } else {
        return mid;
      }
    }

    return left;
  }
}

// export function transformToCSV(list: Record<string, any>[]) {
//   const header = Object.keys(list[0]);
//   const result = [header]
//   for (let i = 0; i < list.length; i++) {
//     const item = list[i];
//     const rows = [];
//     header.forEach((key) => {
//       rows.push(item[key])
//     });
//     result.push(rows);
//   }
//   return result
// }
// export function transformToJSON<T extends Record<string, any>>(list: (string | number)[][]): T[] {
//   const result: T[] = []
//   if (list.length === 0) {
//     return result
//   }
//   const colums = list[0];

//   for (let i = 1; i < list.length; i++) {
//     const row: T = {} as T
//     colums.forEach((key, index) => {
//       row[key as keyof T] = list[i][key]
//     });
//     result.push(row);
//   }
//   return result;
// }

export function transformToCSV(list: Record<string, any>[]) {
  if (!Array.isArray(list) || list.length === 0) {
    return '';
  }
  const header = Object.keys(list[0]).join(',') + '\n';
  const rows = list.map((item) => {
    const values = Object.values(item).map((value) => {
      if (typeof value === 'number') {
        return value;
      } else if (typeof value === 'string') {
        return value;
      } else if (value instanceof Date) {
        return value.toISOString();
      } else if (value instanceof Array) {
        return JSON.stringify(value);
      } else {
        return '';
      }
    });
    return values.join(',') + '\n';
  }).join('');

  return header + rows;
}

const isArrayLikeString = (str) => {
  const regex = /^\[.*?,.*?\]$/;
  return regex.test(str);
};
const isNumberLikeString = (str) => {
  return /^-?\d*\.?\d+$/.test(str);
};

export function transformCSVToJSON<T extends Record<string, any>>(csv: string): T[] {
  if (csv == undefined) {
    return [];
  }
  const lines = csv.trim().split('\n');
  const keys = lines.shift()?.split(',') || [];
  const splitStr = (line: string) => {
    const result = []
    const closingBrackets = {
      '}': 0,
      ']': 0,
    }; 
    let splitStart = 0; 
    for (let i = 0; i < line.length; i++) {
      const char = line[i];
      if (char === '[') {
        closingBrackets[']']++;
        continue
      }
      if (char === ']') {
        closingBrackets[']']--;
        continue
      }
      if (closingBrackets[']'] === 0) {
        if (char === ',') {
          result.push(line.slice(splitStart, i));
          splitStart = i + 1;
        }
      }
    }
    if (splitStart < line.length) {
      result.push(line.slice(splitStart));
    }
    return result;
  }
  return lines.map((line) => {
    const values = splitStr(line);

    const obj: any = {} as T;
    keys.forEach((key, i) => {
      const value = values[i];
      if (isNumberLikeString(value)) {
        obj[key] = parseFloat(value)
      } else if (isArrayLikeString(value)) {
        obj[key] = JSON.parse(value)
      } else {
        obj[key] = value
      }
    });
    return obj;
  });
}

/**
* @param arr 
* @param batchSize 
* @example
* await arraySplitter(largeArray, 5000, async (batch) => {
  // 这里是处理每个小数组的异步回调函数
  console.log(`处理了 ${batch.length} 个元素：${batch}`);
});
*/
export async function arraySplitter<T>(arr: T[], batchSize: number, asyncCallback: (batch: T[]) => Promise<void>): Promise<void> {
  const numBatches = Math.ceil(arr.length / batchSize);
  for (let i = 0; i < numBatches; i++) {
    const start = i * batchSize;
    const end = (i + 1) * batchSize;
    const batch = arr.slice(start, end);
    await asyncCallback(batch);
  }
}